gtkwidget: Avoid poking surfaces and events in gtk_widget_list_devices()
authorCarlos Garnacho <carlosg@gnome.org>
Wed, 24 Jun 2020 09:14:52 +0000 (11:14 +0200)
committerCarlos Garnacho <carlosg@gnome.org>
Wed, 24 Jun 2020 09:14:52 +0000 (11:14 +0200)
This got stuck in ancient times when widgets were windowed, so the devices
in a window to know the devices in that widget would pan out. We do only
want here the devices that are inside the widget, not spread over the
surface, so rewrite this helper function to poke the toplevel foci, and
look they are contained inside the widget.

gtk/gtkwidget.c
gtk/gtkwindow.c
gtk/gtkwindowprivate.h

index 8cb889fef2f0993b965753504fcde2106f747674..0093abb031c0d05ce7eaaaa6592466b814d696f4 100644 (file)
@@ -7548,22 +7548,12 @@ gtk_widget_adjust_baseline_request (GtkWidget *widget,
     }
 }
 
-static gboolean
-is_my_surface (GtkWidget *widget,
-              GdkSurface *surface)
-{
-  if (!surface)
-    return FALSE;
-
-  return gdk_surface_get_widget (surface) == widget;
-}
-
 /*
  * _gtk_widget_list_devices:
  * @widget: a #GtkWidget
  *
  * Returns the list of pointer #GdkDevices that are currently
- * on top of any surface belonging to @widget. Free the list
+ * on top of @widget. Free the list
  * with g_free(), the elements are owned by GTK+ and must
  * not be freed.
  */
@@ -7571,11 +7561,7 @@ GdkDevice **
 _gtk_widget_list_devices (GtkWidget *widget,
                           guint     *out_n_devices)
 {
-  GPtrArray *result;
-  GdkSeat *seat;
-  GList *devices;
-  GList *l;
-  GdkDevice *device;
+  GtkRoot *root;
 
   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
   g_assert (out_n_devices);
@@ -7586,29 +7572,15 @@ _gtk_widget_list_devices (GtkWidget *widget,
       return NULL;
     }
 
-  seat = gdk_display_get_default_seat (_gtk_widget_get_display (widget));
-  if (!seat)
+  root = gtk_widget_get_root (widget);
+  if (!root)
     {
       *out_n_devices = 0;
       return NULL;
     }
-  device = gdk_seat_get_pointer (seat);
-
-  result = g_ptr_array_new ();
-  if (is_my_surface (widget, gdk_device_get_last_event_surface (device)))
-    g_ptr_array_add (result, device);
-
-  devices = gdk_seat_get_physical_devices (seat, GDK_SEAT_CAPABILITY_ALL_POINTING);
-  for (l = devices; l; l = l->next)
-    {
-      device = l->data;
-      if (is_my_surface (widget, gdk_device_get_last_event_surface (device)))
-        g_ptr_array_add (result, device);
-    }
-  g_list_free (devices);
 
-  *out_n_devices = result->len;
-  return (GdkDevice **)g_ptr_array_free (result, FALSE);
+  return gtk_window_get_foci_on_widget (GTK_WINDOW (root),
+                                        widget, out_n_devices);
 }
 
 /*
index 206def4e8938c9860699c3677df06fa63ffd7ca3..c9d3bfd33f4b422dd58c934f9e760c98ab1b8fb6 100644 (file)
@@ -7195,3 +7195,29 @@ gtk_window_destroy (GtkWindow *window)
 
   g_object_unref (window);
 }
+
+GdkDevice**
+gtk_window_get_foci_on_widget (GtkWindow *window,
+                               GtkWidget *widget,
+                               guint     *n_devices)
+{
+  GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
+  GPtrArray *array = g_ptr_array_new ();
+  GList *l;
+
+  for (l = priv->foci; l; l = l->next)
+    {
+      GtkPointerFocus *focus = l->data;
+      GtkWidget *target;
+
+      target = gtk_pointer_focus_get_effective_target (focus);
+
+      if (target == widget || gtk_widget_is_ancestor (target, widget))
+        g_ptr_array_add (array, focus->device);
+    }
+
+  if (n_devices)
+    *n_devices = array->len;
+
+  return (GdkDevice**) g_ptr_array_free (array, FALSE);
+}
index 527e078057c53d8f3e257c262727d464f391c5f4..14a3f8617c800f7dcbc3f8ede0600763d6fb19d1 100644 (file)
@@ -124,6 +124,9 @@ GtkWidget *      gtk_window_pick_popover (GtkWindow   *window,
                                           double       x,
                                           double       y,
                                           GtkPickFlags flags);
+GdkDevice** gtk_window_get_foci_on_widget (GtkWindow *window,
+                                           GtkWidget *widget,
+                                           guint     *n_devices);
 
 G_END_DECLS